/**
 * 
 */
package com.jysz.webcore.ssh.web.struts2;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.util.JRLoader;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.views.jasperreports.JasperReportsResult;
import org.apache.struts2.views.jasperreports.ValueStackDataSource;
import org.apache.struts2.views.jasperreports.ValueStackShadowMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * @author Administrator
 *
 */
public class StrutsJasperReportResult extends JasperReportsResult {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private final Logger LOG = LoggerFactory.getLogger(StrutsJasperReportResult.class);
	protected String jasperFileMap;
	protected String months;
	protected String monthFile;
	protected String reslutFile;
	protected String shopMap;

    /**
     * Sets up result properties, parsing etc.
     *
     * @param invocation Current invocation.
     * @throws Exception on initialization error.
     */
    private void initializeProperties(ActionInvocation invocation) throws Exception {
        if (dataSource == null && connection == null) {
            String message = "No dataSource specified...";
            LOG.error(message);
            throw new RuntimeException(message);
        }
        if (dataSource != null)
            dataSource = conditionalParse(dataSource, invocation);

        format = conditionalParse(format, invocation);
        if (StringUtils.isEmpty(format)) {
            format = FORMAT_PDF;
        }

        if (contentDisposition != null) {
            contentDisposition = conditionalParse(contentDisposition, invocation);
        }

        if (documentName != null) {
            documentName = conditionalParse(documentName, invocation);
        }
        if(jasperFileMap!=null){
        	jasperFileMap=conditionalParse(jasperFileMap, invocation);
        }
        
        if(months!=null){
        	months = conditionalParse(months, invocation);
        }
        if(monthFile != null){
        	monthFile = conditionalParse(monthFile, invocation);
        }
        if(reslutFile != null){
        	reslutFile = conditionalParse(reslutFile, invocation);
        }
        
        if(shopMap != null){
        	shopMap = conditionalParse(shopMap, invocation);
        }        
        
        reportParameters = conditionalParse(reportParameters, invocation);
        exportParameters = conditionalParse(exportParameters, invocation);
    }
    
	/* (non-Javadoc)
	 * @see org.apache.struts2.views.jasperreports.JasperReportsResult#doExecute(java.lang.String, com.opensymphony.xwork2.ActionInvocation)
	 */
	@SuppressWarnings({ "rawtypes", "unchecked"})
	@Override
	  protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {        
        // Will throw a runtime exception if no "datasource" property. TODO Best place for that is...?
        initializeProperties(invocation);

        if (LOG.isDebugEnabled()) {
            LOG.debug("Creating JasperReport for dataSource = " + dataSource + ", format = " + format);
        }
        HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(ServletActionContext.HTTP_RESPONSE);
        // Handle IE special case: it sends a "contype" request first.
        // TODO Set content type to config settings?
        if ("contype".equals(request.getHeader("User-Agent"))) {
            try {
                response.setContentType("application/pdf");
                response.setContentLength(0);

                ServletOutputStream outputStream = response.getOutputStream();
                outputStream.close();
            } catch (IOException e) {
                LOG.error("Error writing report output", e);
                throw new ServletException(e.getMessage(), e);
            }
            return;
        }

        // Construct the data source for the report.
        ValueStack stack = invocation.getStack();
        ValueStackDataSource stackDataSource = null;

        Connection conn = (Connection) stack.findValue(connection);
        if (conn == null)
            stackDataSource = new ValueStackDataSource(stack, dataSource);

        // Determine the directory that the report file is in and set the reportDirectory parameter
        // For WW 2.1.7:
        //  ServletContext servletContext = ((ServletConfig) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONFIG)).getServletContext();
        ServletContext servletContext = (ServletContext) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONTEXT);
        
        String systemId = servletContext.getRealPath(finalLocation);
        Map parameters = new ValueStackShadowMap(stack);
        File directory = new File(systemId.substring(0, systemId.lastIndexOf(File.separator)));
        
        parameters.put("reportDirectory", directory);
        parameters.put(JRParameter.REPORT_LOCALE, invocation.getInvocationContext().getLocale());

        // put timezone in jasper report parameter
        if (timeZone != null) {
            timeZone = conditionalParse(timeZone, invocation);
            final TimeZone tz = TimeZone.getTimeZone(timeZone);
            if (tz != null) {
                // put the report time zone
                parameters.put(JRParameter.REPORT_TIME_ZONE, tz);
            }
        }

        // Add any report parameters from action to param map.
        Map reportParams = (Map) stack.findValue(reportParameters);
        if (reportParams != null) {
            LOG.debug("Found report parameters; adding to parameters...");
            parameters.putAll(reportParams);
        }
       List files = null;
        if(StringUtils.isNotBlank(jasperFileMap)){
        	try{
        		files = (List) stack.findValue(jasperFileMap);	
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        }
        
        List monthList = null;
        if(StringUtils.isNotBlank(months)){
        	try{
        		monthList = (List) stack.findValue(months);	
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        }
        
        if(StringUtils.isNotBlank(monthFile)){
        	try{
        		monthFile = stack.findValue(monthFile).toString();	
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        }
        if(StringUtils.isNotBlank(reslutFile)){
        	try{
        		reslutFile = stack.findValue(reslutFile).toString();	
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        }
        
        Map<Long, String> shopMaps = null;
        if(StringUtils.isNotBlank(shopMap)){
        	try{
        		shopMaps =  (Map<Long, String>)stack.findValue(shopMap);	
        	}catch(Exception e){
        		e.printStackTrace();
        	}
        }
        
        byte[] output;
        JasperPrint jasperPrint = null;
    	List<JasperPrint> jpList = new ArrayList<JasperPrint>();
      	List<String> sheetNamesList = new ArrayList<String>();
        // Fill the report and produce a print object
        try {
        	if(files != null){
        		 for (int i = 0; i < files.size(); i++) {
                 	JasperReport jasperReport = (JasperReport) JRLoader.loadObject(servletContext.getRealPath(files.get(i).toString()));
         			if (conn == null){
         				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
         			}else{
         				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
         			}
         			sheetNamesList.add(jasperPrint.getName());
         			jpList.add(jasperPrint);
         		}
        	}else if(monthList != null && monthList.size() > 0){
        		//FIXME:改成通用导出。。
        		for (Iterator<String> iterator = monthList.iterator(); iterator
						.hasNext();) {
        			JasperReport jasperReport = (JasperReport) JRLoader.loadObject(servletContext.getRealPath(monthFile));
					String month = iterator.next();
					parameters.put("d_month", month);
//					stack.set("d_month", month);
	    			if (conn == null){
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
	    			}else{
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
	    			}
	    			
	    			sheetNamesList.add(month);
	    			jpList.add(jasperPrint);
				}
        		JasperReport jasperReport = (JasperReport) JRLoader.loadObject(servletContext.getRealPath(reslutFile));
    			if (conn == null){
    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
    			}else{
    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
    			}
        		
    			sheetNamesList.add("融资车总量统计");
    			jpList.add(jasperPrint);

        	}else if(shopMaps != null && shopMaps.size() > 0){
        		JasperReport jasperReport = (JasperReport) JRLoader.loadObject(systemId);
        		for (Iterator<Long> iterator = shopMaps.keySet().iterator(); iterator
						.hasNext();) {
        			Long key =  iterator.next();
        			parameters.put("SHOP_ID", key);
        			parameters.put("SHOP_NAME", shopMaps.get(key));
	    			if (conn == null){
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
	    			}else{
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
	    			}
	    			
	    			sheetNamesList.add(shopMaps.get(key));
	    			jpList.add(jasperPrint);
				}
        	}else{
	        		JasperReport jasperReport = (JasperReport) JRLoader.loadObject(systemId);
	    			if (conn == null){
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
	    			}else{
	    				jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
	    			}
        		}
             } catch (JRException e) {
            LOG.error("Error building report for uri " + systemId, e);
            throw new ServletException(e.getMessage(), e);
        }
        // Export the print object to the desired output format
        try {
            if (contentDisposition != null || documentName != null) {
                final StringBuffer tmp = new StringBuffer();
                tmp.append((contentDisposition == null) ? "inline" : contentDisposition);

                if (documentName != null) {
                    tmp.append("; filename=");
                    tmp.append(documentName);
                    tmp.append(".");
                    tmp.append(format.toLowerCase());
                }

                response.setHeader("Content-disposition", tmp.toString());
            }

            JRExporter exporter;

            if (format.equals(FORMAT_PDF)) {
                response.setContentType("application/pdf");
                exporter = new JRPdfExporter();
            } else if (format.equals(FORMAT_CSV)) {
                response.setContentType("text/plain");
                exporter = new JRCsvExporter();
            } else if (format.equals(FORMAT_HTML)) {
                response.setContentType("text/html");

                // IMAGES_MAPS seems to be only supported as "backward compatible" from JasperReports 1.1.0
                Map imagesMap = new HashMap();
                request.getSession(true).setAttribute("IMAGES_MAP", imagesMap);

                exporter = new JRHtmlExporter();
                exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP, imagesMap);
                exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI, request.getContextPath() + imageServletUrl);

                // Needed to support chart images:
                exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
                request.getSession().setAttribute("net.sf.jasperreports.j2ee.jasper_print", jasperPrint);
            } else if (format.equals(FORMAT_XLS)) {
                response.setContentType("application/vnd.ms-excel");
                exporter = new JRXlsExporter();
                if(files!=null || monthList != null || shopMaps != null){
                	  //获取sheet名称
    				String[] sheetNameArray = new String[sheetNamesList.size()];
    				 int strIndex = 0;
    				   for (int i = 0; i < sheetNameArray.length; i++) {
    				    sheetNameArray[strIndex] = (String) sheetNamesList.get(i);
    				    strIndex++;
    				   }
    				   exporter.setParameter(JRXlsExporterParameter.SHEET_NAMES,sheetNameArray);//设置sheet名称
    				   exporter.setParameter(JRXlsExporterParameter.JASPER_PRINT_LIST, jpList);
                }
            } else if (format.equals(FORMAT_XML)) {
                response.setContentType("text/xml");
                exporter = new JRXmlExporter();
            } else if (format.equals(FORMAT_RTF)) {
            	
                response.setContentType("application/rtf");
                exporter = new JRRtfExporter();
            } else {
                throw new ServletException("Unknown report format: " + format);
            }

            Map exportParams = (Map) stack.findValue(exportParameters);
            if (exportParams != null) {
                LOG.debug("Found export parameters; adding to exporter parameters...");
                exporter.getParameters().putAll(exportParams);
            }
            
            output = exportReportToBytes(jasperPrint, exporter);
        } catch (JRException e) {
           String message = "Error producing " + format + " report for uri " + systemId;
            LOG.error(message, e);
            throw new ServletException(e.getMessage(), e);
        }

        response.setContentLength(output.length);

        // Will throw ServletException on IOException.
        writeReport(response, output);
    }

	/**
     * Run a Jasper report to CSV format and put the results in a byte array
     *
     * @param jasperPrint The Print object to render as CSV
     * @param exporter    The exporter to use to export the report
     * @return A CSV formatted report
     * @throws net.sf.jasperreports.engine.JRException
     *          If there is a problem running the report
     */
    private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws JRException {
        byte[] output;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
        if (delimiter != null) {
            exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, delimiter);
        }
        exporter.exportReport();

        output = baos.toByteArray();

        return output;
    }

    /**
     * Writes report bytes to response output stream.
     *
     * @param response Current response.
     * @param output   Report bytes to write.
     * @throws ServletException on stream IOException.
     */
    private void writeReport(HttpServletResponse response, byte[] output) throws ServletException {
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(output);
            outputStream.flush();
        } catch (IOException e) {
            LOG.error("Error writing report output", e);
            throw new ServletException(e.getMessage(), e);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                LOG.error("Error closing report output stream", e);
                throw new ServletException(e.getMessage(), e);
            }
        }
    }
	/**
	 * @return the jasperFileMap
	 */
	public String getJasperFileMap() {
		return jasperFileMap;
	}

	/**
	 * @param jasperFileMap the jasperFileMap to set
	 */
	public void setJasperFileMap(String jasperFileMap) {
		this.jasperFileMap = jasperFileMap;
	}

	public String getMonths() {
		return months;
	}

	public void setMonths(String months) {
		this.months = months;
	}

	public String getMonthFile() {
		return monthFile;
	}

	public void setMonthFile(String monthFile) {
		this.monthFile = monthFile;
	}

	public String getReslutFile() {
		return reslutFile;
	}

	public void setReslutFile(String reslutFile) {
		this.reslutFile = reslutFile;
	}

	public String getShopMap() {
		return shopMap;
	}

	public void setShopMap(String shopMap) {
		this.shopMap = shopMap;
	}

	
}
